package emusic.preview 
{
	import emusic.api.clients.AlbumClient;
	import emusic.api.clients.AlbumSearchRequest;
	import emusic.api.clients.ArtistClient;
	import emusic.api.clients.ArtistSearchRequest;
	import emusic.api.clients.M3UClient;
	import emusic.api.data.AlbumData;
	import emusic.api.data.SampleTrackData;
	import emusic.api.data.SummaryData;
	import emusic.api.EMusicClient;
	import emusic.api.events.AlbumSearchEvent;
	import emusic.api.events.ArtistSearchEvent;
	import emusic.api.events.M3UEvent;
	import emusic.api.feeds.AlbumFeed;
	import emusic.api.feeds.SampleTrackFeed;
	import emusic.ws.PaginationInfo;
	import flash.events.EventDispatcher;
	import newcommerce.data.MediaData;
	import newcommerce.events.MediaEvent;
	import newcommerce.media.MP3Player;
	
	/**
	 * ...
	 * @author Martin Legris ( http://blog.martinlegris.com )
	 */
	
	 /**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.AlbumPreviewEvent.ALBUM_NOT_FOUND
	 */
	[Event(name="album_not_found_event", type="emusic.preview.AlbumPreviewEvent")] 

	/**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.AlbumPreviewEvent.ALBUM_FOUND
	 */
	[Event(name="album_found_event", type="emusic.preview.AlbumPreviewEvent")] 
	
	/**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.AlbumPreviewEvent.ALBUM_PLAYING
	 */
	[Event(name="album_playing_event", type="emusic.preview.AlbumPreviewEvent")] 

	/**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.AlbumPreviewEvent.ALBUM_ENDED
	 */
	[Event(name="album_ended_event", type="emusic.preview.AlbumPreviewEvent")] 

	/**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.AlbumPreviewEvent.ARTIST_FOUND
	 */
	[Event(name="artist_found_event", type="emusic.preview.AlbumPreviewEvent")] 
	
	/**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.AlbumPreviewEvent.ARTIST_NOT_FOUND
	 */
	[Event(name="artist_not_found_event", type="emusic.preview.AlbumPreviewEvent")] 

	/**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.SongPreviewEvent.SONG_PLAYING
	 */
	[Event(name="song_playing_event", type="emusic.preview.SongPreviewEvent")] 
	
	/**
	 [broadcast event] Dispatched when ...
	 @eventType	emusic.preview.SongPreviewEvent.SONG_ENDED
	 */
	[Event(name="song_ended_event", type="emusic.preview.SongPreviewEvent")] 
	
	public class AlbumPreviewer extends EventDispatcher
	{
		protected var _artistName:String;
		protected var _artistId:int = -1;
		protected var _albumName:String;
		protected var _albumId:int = -1;
		protected var _sampleUrl:String;
		protected var _totalAlbums:Number = 0;
		
		protected var _artistRequestId:int = -1
		protected var _albumRequestId:int = -1;
		protected var _m3uRequestId:int = -1;
		
		protected var _player:MP3Player;
		protected var _artistWs:ArtistClient;
		protected var _albumWs:AlbumClient;
		protected var _m3uWs:M3UClient;
		protected var _emusic:EMusicClient;
		protected var _sampleFeed:SampleTrackFeed;
		
		protected var _playingAlbumName:String;
		protected var _playingArtistName:String;
		
		protected var _currentAlbum:AlbumData;
		protected var _albums:Array;
		
		public function get artistName():String { return _artistName; }
		
		public function AlbumPreviewer() 
		{
			_emusic = EMusicClient.getInstance();
			
			_artistWs = _emusic.artist;
			_artistWs.addEventListener(ArtistSearchEvent.SUCCESS, doArtistResult);
			
			_albumWs = _emusic.album;
			_albumWs.addEventListener(AlbumSearchEvent.SUCCESS, doAlbumResult);
			
			_m3uWs = M3UClient.getInstance();
			_m3uWs.addEventListener(M3UEvent.M3U_RECEIVED, doSamplesReady);
			
			_player = MP3Player.getInstance();
			_player.addEventListener(MediaEvent.MEDIA_FINISHED_PLAYING, doMediaFinished);			
			_player.addEventListener(MediaEvent.MEDIA_DURATION, doMediaDuration);
			_player.addEventListener(MediaEvent.INVALID_MEDIA, doMediaInvalid);
			_player.addEventListener(MediaEvent.MEDIA_TIME, doMediaTime);
			_albums = [];
		}
		
		public function preview(artistName:String, albumName:String):void
		{
			clearPendingRequests();
			
			_sampleUrl = "";
			
			if (_artistName != null && compareArtistNames(_artistName, artistName) && _artistId != -1)
			{
				if (_albumName.toLowerCase() != albumName.toLowerCase())
				{
					_albumId = -1;
					_currentAlbum = null;
					_albumName = albumName;
				}
					
				if (_albums.length != 0)
				{
					// try to find the album in the list
					var album:AlbumData;
					for (var i:Number = 0; i < _albums.length; i++)
					{
						album = _albums[i];
						if (_albumName.toLowerCase() == album.name.toLowerCase() && compareArtistNames(album.artist.name, _artistName))
						{
							_sampleUrl = album.sample;
							_currentAlbum = album;
							_albumId = album.id;
							startPreview();
						}
					}
					
					if (_sampleUrl == "" && _albums.length != _totalAlbums)
					{
						trace("_albums length[" + _albums.length + "] floor result[" + Math.floor(_albums.lenght / 20) + "]");
						searchForAlbumsByArtistId(_artistId, Math.ceil(_albums.length / 20));
					}
					else if (_sampleUrl == "")
					{
						dispatchEvent(new AlbumPreviewEvent(AlbumPreviewEvent.ALBUM_NOT_FOUND, null, _artistName, _albumName));
					}
				}
				else
					searchForAlbumsByArtistId(_artistId);
			}
			else
			{
				_artistId = -1;
				_albumId = -1;
				_artistName = artistName;
				_albumName = albumName;
				searchForArtist(artistName);
			}
		}
		
		protected function searchForArtist(artist:String):void
		{
			var params:ArtistSearchRequest = new ArtistSearchRequest();
			params.term = artist;
			_artistId = -1;
			_albums = [];
			_artistRequestId = _artistWs.search(params);
		}
		
		protected function compareArtistNames(name1:String, name2:String):Boolean
		{
			name1 = name1.toLowerCase();
			name2 = name2.toLowerCase();
			if (name1.indexOf("the ") == 0)
				name1 = name1.substr(4);
				
			if (name2.indexOf("the ") == 0)
				name2 = name2.substr(4);
				
			trace("artist1[" + name1 + "] artist2[" + name2 + "]");
				
			return name1 == name2;
		}
		
		protected function doArtistResult(evt:ArtistSearchEvent):void
		{
			trace("doArtistResult[" + evt.requestId + "]");
			
			if (evt.requestId != _artistRequestId)
				return;
			
			_artistId = -1;
			
			var artist:SummaryData;
			while (artist = evt.feed.next())
			{
				trace("comparing [" + _artistName + "] to [" + artist.name + "]");
				if (compareArtistNames(_artistName, artist.name))
				{
					_artistId = artist.id;
					break;
				}
			}
			
			if (_artistId != -1)
			{
				dispatchEvent(new AlbumPreviewEvent(AlbumPreviewEvent.ARTIST_FOUND, null, _artistName, null));
				searchForAlbumsByArtistId(_artistId);
			}
			else
			{
				dispatchEvent(new AlbumPreviewEvent(AlbumPreviewEvent.ARTIST_NOT_FOUND, null, _artistName, null));
			}
		}
		
		protected function searchForAlbumsByArtistId(artistId:Number, startPage:Number = 1):void
		{
			trace("searchForAlbumsByArtistId(" + artistId + "," + startPage + ")");
			var params:AlbumSearchRequest = new AlbumSearchRequest();
			params.artistId = artistId;
			params.pagination.page = startPage;
			_albumRequestId = _albumWs.search(params);
		}
		
		protected function doAlbumResult(evt:AlbumSearchEvent):void
		{
			trace("doAlbumResult[" + evt.requestId + "]");
			
			if (evt.requestId != _albumRequestId)
				return;
			
			_albumId = -1;
			
			var feed:AlbumFeed = evt.feed;
			var pagination:PaginationInfo = evt.pagination;
			var album:AlbumData;
			
			if (pagination.page == 1)
			{
				_albums = [];
				_totalAlbums = pagination.total;
			}
				
			while (album = feed.next())
			{
				_albums.push(album);
				
				if (album.name.toLowerCase() == _albumName.toLowerCase() && compareArtistNames(album.artist.name, _artistName))
				{
					_albumId = album.id;
					_sampleUrl = album.sample;
					_currentAlbum = album;
					trace("[" + album.artist.name +"] " + album.name + " -- is the one!");
				}
				else
				{
					trace("[" + album.artist.name + "] " + album.name + " -- not the one..");
				}
			}
			
			if (_albumId == -1)
			{
				// continue the search..
				if (pagination.page < pagination.pages)
				{
					pagination.page++;
					var request:AlbumSearchRequest = new AlbumSearchRequest();
					if(_artistId != -1)
						request.artistId = _artistId;
					else
						request.term = _albumName;
						
					request.pagination = pagination;
					_albumRequestId = _albumWs.search(request);
				}
				else
				{
					dispatchEvent(new AlbumPreviewEvent(AlbumPreviewEvent.ALBUM_NOT_FOUND, null, _artistName, _albumName)); 
				}
			}
			else
			{
				dispatchEvent(new AlbumPreviewEvent(AlbumPreviewEvent.ALBUM_FOUND, null, _artistName, _albumName));
				startPreview();
			}
		}
		
		protected function startPreview():void
		{
			_m3uRequestId = _m3uWs.getByUrl(_sampleUrl);
		}
		
		protected function doSamplesReady(evt:M3UEvent):void
		{
			trace("doSamplesReady[" + evt.requestId + "]");
			
			if (evt.requestId != _m3uRequestId)
				return;
				
			_playingAlbumName = _albumName;
			_playingArtistName = _artistName;
			
			_sampleFeed = evt.feed;
			_sampleFeed.first();
			_sampleFeed.next();
			trace("we have:" + _sampleFeed.count + " medias");
			dispatchEvent(new AlbumPreviewEvent(AlbumPreviewEvent.ALBUM_PLAYING, _currentAlbum));
			next();
		}
		
		protected function doMediaFinished(evt:MediaEvent):void
		{
			trace("doMediaFinished");
			try { dispatchEvent(new SongPreviewEvent(SongPreviewEvent.SONG_ENDED, _sampleFeed.current().name, _playingAlbumName, _playingArtistName)); } catch(e:TypeError) {}
			next();
		}
		
		protected function doMediaDuration(evt:MediaEvent):void
		{
			trace("doMediaDuration " + evt.get("duration"));
			_player.currentMedia.duration = 30;
		}
		
		protected function doMediaTime(evt:MediaEvent):void
		{
			//trace("doMediaTime:" + evt.get("seconds"));
		}
		
		protected function doMediaInvalid(evt:MediaEvent):void
		{
			trace("doMediaInvalid");
		}
		
		public function nextSong():void
		{
			next();
		}
		
		public function previousSong():void
		{
			previous();
		}
		
		protected function next():void
		{
			var track:SampleTrackData = _sampleFeed.next();
			
			if (track != null)
				playTrack(track);
			else
				albumEnded();
		}
		
		protected function previous():void
		{
			var track:SampleTrackData = _sampleFeed.previous();
			
			if (track != null)
				playTrack(track);
		}
		
		protected function albumEnded():void
		{
			dispatchEvent(new AlbumPreviewEvent(AlbumPreviewEvent.ALBUM_ENDED, _currentAlbum));
		}
		
		protected function playTrack(track:SampleTrackData):void
		{
			 _player.playMedia(new MediaData( -1, track.name, track.length, track.url));
			dispatchEvent(new SongPreviewEvent(SongPreviewEvent.SONG_PLAYING, track.name, _playingAlbumName, _playingArtistName));
		}
		
		protected function clearPendingRequests():void
		{
			_artistRequestId = -1;
			_albumRequestId = -1;
			_m3uRequestId = -1;
		}
		
		public function stopPreview():void
		{
			_player.stop();
		}
	}
}